package com.oneplus.extend.compiler;

import com.oneplus.exception.BusinessException;
import com.oneplus.exception.ErrorCode;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.spongycastle.util.encoders.Hex;

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;


public class MyClassLoader extends ClassLoader {

    public static String compilerContract(String contractStr) {
        StringBuffer bin = new StringBuffer();
        List<String> classNames = Pcompiler.getMember(contractStr, "(public[\\s]+class[\\s]+[^{]*|class[\\s]+[^{]*)");
//        if (classNames.size() > 1) {
//            throw new BusinessException("目前只支持单个类", ErrorCode._10042);
//        }
        //解析类名 start
        String name = null;
        for (int i = 0; i < classNames.size(); i++) {
            String[] c = ArrayUtils.removeAllOccurences(classNames.get(i).split(" "), "");
            if (c[0].equals("public")) {
                name = c[2];
            }
        }
        if (classNames.size() == 1) {
            String[] c = classNames.get(0).split(" ");
            name = c[2];
        }
        if (!checkSingle(contractStr)) {
            throw new BusinessException("目前不支持外部类", ErrorCode._10042);
        }
        //end
        if (StringUtils.isNotBlank(name)) {
            String classurl = string2File(contractStr, name);
            String cmd = "javac.exe -encoding utf-8 " + System.getProperty("user.dir") + File.separator + name + ".java";
            try {
                Runtime.getRuntime().exec(cmd);
                Thread.sleep(1000);
                ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
                // This URL for a directory will be searched *recursively*
//                String file = System.getProperty("user.dir") + File.separator + name + ".class";

                String regex = "^" + (System.getProperty("user.dir") + File.separator).replace("\\", "/") + name + "[\\s\\S]*.class$";

                File readFile = new File(System.getProperty("user.dir") + File.separator);
                List<File> fileList = new ArrayList<>();
                if (readFile.isDirectory()) {
                    File[] files = readFile.listFiles();
                    for (File dirfile : files) {
                        if (test(dirfile, regex)) {
                            fileList.add(dirfile);
                        }
                    }
                }
                for (File f : fileList) {
                    bin.append(Hex.toHexString(new MyClassLoader().getClassByte(f.getAbsolutePath())));
                    if (StringUtils.isNotBlank(bin)) {
                        bin.append(",");
                        f.delete();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                throw new BusinessException("合约代码有误", ErrorCode._10001);
            } finally {//删除java文件
//                File file0 = new File(System.getProperty("user.dir") + File.separator + name + ".java");
//                file0.delete();
            }
        }
        if(bin.length() > 1){
            bin = bin.delete(bin.length()-1,bin.length());
        }
        return bin.toString();
    }

    public byte[] getClassByte(String file) throws Exception {
        return Files.readAllBytes(new File(file).toPath());
    }

    public static boolean test(File readFile, String regex) {
        String fileName = readFile.getAbsolutePath().replace("\\", "/");
        if (fileName.matches(regex)) {
            return true;
        }
        return false;
    }

    public static String string2File(String res, String name) {
        String file = System.getProperty("user.dir") + File.separator + name + ".java";
        BufferedReader bufferedReader = null;
        BufferedWriter bufferedWriter = null;
        try {
            File distFile = new File(file);
            if (!distFile.getParentFile().exists()) distFile.getParentFile().mkdirs();
            bufferedReader = new BufferedReader(new StringReader(res));
//            bufferedWriter = new BufferedWriter(new FileWriter(distFile));
            bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(distFile),"UTF-8"));
            char buf[] = new char[1024];         //字符缓冲区
            int len;
            while ((len = bufferedReader.read(buf)) != -1) {
                bufferedWriter.write(buf, 0, len);
            }
            bufferedWriter.flush();
            bufferedReader.close();
            bufferedWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
            return file;
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return file;
    }

    public Class loadClass() {
        byte[] code = Hex.decode("cafebabe00000034002a0a0008002209000700230800240900070025090007002609000700270700280700290100046e616d650100124c6a6176612f6c616e672f537472696e673b01000673796d626f6c01000469636f6e010008646563696d616c73010001490100063c696e69743e010003282956010004436f646501000f4c696e654e756d6265725461626c6501000967657453796d626f6c01001428294c6a6176612f6c616e672f537472696e673b01000973657453796d626f6c010015284c6a6176612f6c616e672f537472696e673b29560100076765744e616d650100077365744e616d6501005d284c6a6176612f6c616e672f537472696e673b4c6a6176612f6c616e672f537472696e673b4c6a6176612f6c616e672f537472696e673b4c6a6176612f6c616e672f537472696e673b4c6a6176612f6c616e672f537472696e673b295601000767657449636f6e01000773657449636f6e01000b676574446563696d616c7301000328294901000b736574446563696d616c730100042849295601000a536f7572636546696c650100086162632e6a6176610c000f00100c000b000a01000a736466647366736466610c0009000a0c000c000a0c000d000e0100036162630100106a6176612f6c616e672f4f626a6563740021000700080000000400020009000a00000002000b000a00000002000c000a00000002000d000e000000090001000f0010000100110000001d00010001000000052ab70001b100000001001200000006000100000001000100130014000100110000001d00010001000000052ab40002b000000001001200000006000100000008000100150016000100110000002200020002000000062a2bb50002b10000000100120000000a00020000000c0005000d000100170014000100110000001b00010001000000031203b000000001001200000006000100000010000100180019000100110000002200020006000000062a2bb50004b10000000100120000000a000200000014000500150001001a0014000100110000001d00010001000000052ab40005b0000000010012000000060001000000180001001b0016000100110000002200020002000000062a2bb50005b10000000100120000000a00020000001c0005001d0001001c001d000100110000001d00010001000000052ab40006ac000000010012000000060001000000200001001e001f000100110000002200020002000000062a1bb50006b10000000100120000000a0002000000240005002500010020000000020021");
        Class c1 = defineClass(code, 0, code.length);
        return c1;
    }

    public List<Class> binToClass(String bin) {
        String[] bins = bin.split(",");
        List<Class> list = new ArrayList<>();
        if (bins.length == 0) {
            byte[] code = Hex.decode(bin);
            Class c1 = defineClass(code, 0, code.length);
            list.add(c1);
        } else {
            for (String b : bins) {
                byte[] code = Hex.decode(b);
                Class c1 = defineClass(code, 0, code.length);
                list.add(c1);
            }
        }
        return list;

    }

    private static Boolean checkSingle(String str) {
        String temp = getContent(str, "{", "}");
        str = str.replace(temp, "");
        if (str.contains("{") || str.contains("}")) {
            return false;
        }
        return true;
    }

    //获取括号里面内容
    public static String getContent(String str, String head, String end) {
        if (str.indexOf(head) > 0) {
            str = str.substring(str.indexOf(head));
            int he = 0;
            int en = 0;
            int index = 0;
            for (int i = 0; i < str.length(); i++) {
                if (head.equals(String.valueOf(str.charAt(i)))) {
                    he++;
                }
                if (end.equals(String.valueOf(str.charAt(i)))) {
                    en++;
                }
                if (he == en) {
                    index = i;
                    break;
                }
            }
            str = str.substring(0, index + 1);
        }
        return str;
    }

}